/********************************************************************
* プロジェクト名: GPSLogger3
* PIC24F64GB002 + SDカード + カシミール3D対応
* GPSモジュールの設定はデフォルトのまま WGS84

********************************************************************/

#include <p24fj64gb002.h>
#include "USB/USB.h"
#include "HardwareProfile.h"
#include "USB/usb_function_cdc.h"
#include "MDD File System/SD-SPI.h"
#include "MDD File System/FSIO.h"
#include "USB/usb_function_msd.h"
#include "lcd_i2c_lib2.h"
#include <math.h>


_CONFIG1(WINDIS_OFF & FWDTEN_OFF & ICS_PGx1 & GCP_OFF & JTAGEN_OFF & GWRP_OFF)
_CONFIG2(POSCMOD_HS & I2C1SEL_PRI & OSCIOFNC_OFF & FCKSM_CSDCMD
& FNOSC_PRIPLL & PLL96MHZ_ON & PLLDIV_DIV2 & IESO_OFF)
_CONFIG3(SOSCSEL_IO)

#pragma udata
/* USB MSDクラス用関数呼び出しポインタ */
LUN_FUNCTIONS LUN[MAX_LUN + 1] =
{
{
&MDD_SDSPI_MediaInitialize, // メディア初期化
&MDD_SDSPI_ReadCapacity, // 容量読み出し
&MDD_SDSPI_ReadSectorSize, // セクタサイズ読み出し
&MDD_SDSPI_MediaDetect, // メディア検出
&MDD_SDSPI_SectorRead, // 1セクタ読み出し
&MDD_SDSPI_WriteProtectState, // 保護状態読み出し
&MDD_SDSPI_SectorWrite // セクタ書き込み
}
};
FSFILE *logFile;
BOOL initResults;
/* USB MSDクラスのSCSI INQUIRYコマンド応答用データ */
const ROM InquiryResponse inq_resp = {
0x00, // peripheral device is connected, direct access block device
0x80, // RMB removable
0x04, // ISO version=0, ECMA version=0, ANSI version=4=SPC-2
0x02, // response is in format specified by SPC-2
0x20, // Additional Length(n-4) = 36-4=32= 0x20
0x00, // sccs etc.
0x00, // etc
0x00, //bque=1 and cmdque=0,indicates simple queueing 00 is obsolete,
// but as in case of other device, we are just using 00
// 00 obsolete, 0x80 for basic task queueing
{'F','.','T','o','y','o','s',' '}, // T10 Vendor ID 8cha
{'G','P','S',' ','U','S','B',' ','L','o','g','g','e','r',' ',' '},//product ID 16cha
{'0','0','0','1'} // product revison 4cha
};

extern unsigned char SPIBuf[];
char SavBuf[256]; // 受信用バッファ
#define Max 256 // バッファサイズ
char GGABuf[Max]; // 77byte
char GSABuf[Max]; // 47byte
char GSVBuf[Max]; // 60byte 5秒に1回
char RMCBuf[Max]; // 72byte
char VTGBuf[Max]; // 38byte
int GGASize, GLLSize, GSASize, GSVSize;
int GSVSize, RMCSize, VTGSize, ZDASize;
int Ptr, Size, Index, SendFlag, SendState;
char Flag, DFlag, temp, LogCnt;
unsigned int BatV;
unsigned long LogAdr;
char USBOutBuf[64];

int hour; i;
unsigned int n, nn, nnn;
unsigned int X, Y, XX, YY;
char buf[46];
unsigned char buff[4], bufff[4];




const unsigned char StrMsg[] = "Start GPS Logger";
const unsigned char USBMsg[] = "Connect to USB! ";
const unsigned char TXSMsg[] = "Start USB Send! ";
const unsigned char TXEMsg[] = "Stop USB Send! ";


static void InitializeSystem(void);
void USBDeviceTasks(void);
void USBCBSendResume(void);
void PosDisp(void);
void TimeDisp(void);
char Receive(void);
void Send(char Data);
void Battery(void);
void Logging(void);
void USBSend(void);

#pragma code




int main(void)
{
InitializeSystem(); // システム初期化

Ptr = 0;
DFlag = 0; // 表示モードフラグ
GGASize = 0; // センテンス受信カウンタリセット
GSASize = 0;
GSVSize = 0;
RMCSize = 0;
VTGSize = 0;
logFile = NULL; // ログファイル未オープンにリセット

initResults = FSInit(); // ファイルシステム初期化
USBDeviceInit(); // USBデバイス初期化
USBDeviceAttach(); // USBデバイスアタッチ許可

n = 0; nn = 0;


while(1)
{
/********** USB接続中の場合 *************/
if((USBDeviceState >= CONFIGURED_STATE)&&(USBSuspendControl!=1)){
MSDTasks(); // ファイルシステムステート更新
/*** USB CDCコマンド受信 ***/
if(getsUSBUSART(USBOutBuf,64) > 0){ // データ受信ポール
switch(USBOutBuf[0]){ // 最初の1文字チェック
case 's': // 送信開始
lcd_str(TXSMsg); // 送信開始メッセージ表示
SendFlag = 1; // 送信中フラグオン
SendState = 1;
break;
case 'e': // 送信終了
lcd_str(TXEMsg); // 送信終了メッセージ表示
SendFlag = 0; // 送信中フラグオフ
break;
}
}
/**** USB CDCデータ送信実行ステート *******/
if((SendFlag ==1) && (VTGSize != 0)) // 全センテンス受信完了待ち
USBSend(); // 全センテンスをステートで送信
}
/********** USB接続なしの場合 ***********/
else{

if(sw2){
DFlag ^= 1; // 表示切替反転
lcd_clear();
while(sw2);
delay_ms(50);
}

if(sw1){
if(logFile != NULL){ // ログ中か?
FSfclose(logFile); // ファイルクローズ
logFile = NULL; // ログ中フラグリセット
LUNSoftAttach(0); // CPUから直ぐアタッチ確認
lcd_icon(3, 0);
lcd_icon(2, 0);
}
else{
LUNSoftDetach(0); // CPUアクセス禁止
logFile = FSfopen("GPSLog.csv",APPEND);
lcd_icon(3, 1);
}
while(sw1);
delay_ms(50);
}

if(VTGSize != 0){

if(Flag){
Flag = 0;
lcd_icon(0, 1);
}
else{
Flag = 1;
lcd_icon(0, 0);
}

if(DFlag == 0) // 表示モードチェック
PosDisp();
else
TimeDisp();

Battery();

if(logFile != NULL){
if(GSABuf[9] > '1'){
if(Flag)
lcd_icon(2,1); // ログ中目印アイコン点滅
else
lcd_icon(2, 0);
Logging();
}
}

GGASize = 0;
GSASize = 0;
GSVSize = 0;
RMCSize = 0;
VTGSize = 0;
}
else
delay_ms(10);
}
}
return 0;
}



static void InitializeSystem(void)
{
CLKDIV = 0x0020; // 96MHz PLL On, CPU32MHz
AD1PCFG = 0xFFFD; // AN1以外デジタルに設定
/* I/Oモード設定 */
TRISA = 0x000E;
TRISB = 0x8FE7;
/* I2Cの初期設定 */
I2C1BRG = 0x9D; // 100kHz@16MHz
I2C1CON = 0x8000; // I2Cイネーブル
/* SPIピン割付 */
RPINR20bits.SDI1R = 15; // SDI1 -> RP15
RPOR6bits.RP13R = 7; // SDO1 -> RP13
RPOR7bits.RP14R = 8; // SCK1OUT -> RP14
/// ADコンバータの初期設定
AD1CON1 = 0x00E0; // ADオン、手動サンプル開始,自動変換開始
AD1CON2 = 0x0000; // AVdd, AVss, 変換ごとに割り込み, MUXAのみ
AD1CON3 = 0x1F05; // 31 Tad auto-sample, Tad = 5*Tcy
AD1CHS = 0x0001; // チャネル選択(AN1)
AD1CSSL = 0; // 自動スキャンなし//
/* 液晶表示器の初期化 */
lcd_init(); // 初期化
lcd_cmd(0x80); // 1行目
lcd_str(StrMsg); // 開始メッセージ表示
delay_ms(500); // 表示確認待ち
/// UART1ピン割付
RPINR18bits.U1RXR = 2; // UART1 RX to RP2
RPOR1bits.RP3R = 3; // UART1 TX to RP3
/// UART1初期設定 4800bps 8ビット パリティなし、フロー制御なし
U1BRG = 207; // 4800bps@16MHz
U1MODE = 0b1000100000000000; // UART1初期設定
U1STA = 0b0000010000000000; // UART1初期設定
IFS0bits.U1RXIF = 0; // 受信割り込みフラグクリア
IEC0bits.U1RXIE =1; // 受信割り込み許可
}





void __attribute__((interrupt, no_auto_psv)) _U1RXInterrupt(void)
{
char data;

IFS0bits.U1RXIF = 0; // 割り込みフラグクリア
if(U1STAbits.OERR|| U1STAbits.FERR) {
lcd_icon(4, 1); // Error log on
Ptr = 0; // バッファポインタリセット
U1STA &= 0xFFF0; // エラーフラグクリア
U1MODE = 0; // UART Disable
U1MODE = 0b1000100000000000; // UART1初期設定
U1STA = 0b0000010000000000; // UART1初期設定
IEC0bits.U1RXIE =1; // 受信割り込み許可
}
else {
data = U1RXREG; // 受信データ取得
if(Ptr < 200)
SavBuf[Ptr++] = data; // 格納
else{
lcd_icon(5, 1); // Error
Ptr = 0;
}
if(data == 0x0A){ // センテンス終了か
Size = Ptr; // 受信バイト数保存
Ptr = 0; // ポインタリセット

if(memcmp(SavBuf, "$GPGGA", 6)==0){
memcpy(GGABuf, SavBuf, Size); // バッファコピー
GGASize = Size; // 受信バイト数保存

hour = (GGABuf[7]-'0')*10 + (GGABuf[8]-'0') + 9;
if(hour > 23) hour = hour - 24;
GGABuf[8] = (hour%10) + '0';
hour = hour/10;
GGABuf[7] = (hour%10) + '0';

}
else if(memcmp(SavBuf, "$GPGSA", 6)==0){
memcpy(GSABuf, SavBuf, Size);
GSASize = Size;
}
else if(memcmp(SavBuf, "$GPGSV", 6)==0){
memcpy(GSVBuf, SavBuf, Size);
GSVSize = Size;
}
else if(memcmp(SavBuf, "$GPRMC", 6)==0){
memcpy(RMCBuf, SavBuf, Size);
RMCSize = Size;
}
else if(memcmp(SavBuf, "$GPVTG", 6)==0){
memcpy(VTGBuf, SavBuf, Size);
VTGSize = Size;
}
}
}
}



void USBSend(void){
switch(SendState){
case 1:
if(USBUSARTIsTxTrfReady()){
if(GGASize != 0)
putUSBUSART(buf, 44);
SendState++;
}
break;
case 2:
if(USBUSARTIsTxTrfReady()){
GGASize = 0;
GSASize = 0;
GSVSize = 0;
RMCSize = 0;
VTGSize = 0;
SendState++;

}
break;
default:
break;
}
CDCTxService();
}





void Logging(void){
if(GGASize != 0)

n = n + 1;
if(n > 9){
nn++; n = 0; nnn = nn;

X = atoi(& GGABuf[23]);
XX = X*6/10;

i = 3;
do{
buff[i] = (XX % 10) + '0';
XX = XX/10;
i--;
} while(XX > 0);

Y = atoi(& GGABuf[36]);
YY = Y*6/10;

i = 3;
do{
bufff[i] = (YY % 10) + '0';
YY = YY/10;
i--;
} while(YY > 0);


buf[0] = 'W';

for(i=1;i<6;i++) buf[i] = ' ';
i = 5;
do{
buf[i] = (nnn % 10) + '0';
nnn = nnn/10;
i--;
} while(nnn > 0);

buf[6] = ','; buf[7] = ',';

buf[8] = GGABuf[18]; buf[9] = GGABuf[19];
buf[10] = '.';
buf[11] = GGABuf[20]; buf[12] = GGABuf[21];
for(i=13;i<16;i++) buf[i] = '0';
buf[13] = buff[0]; buf[14] = buff[1]; buf[15] = buff[2];
buf[16] = ',';

buf[17] = GGABuf[30]; buf[18] = GGABuf[31]; buf[19] = GGABuf[32];
buf[20] = '.';
buf[21] = GGABuf[33]; buf[22] = GGABuf[34];
for(i=23;i<26;i++) bufff[i] = '0';
buf[23] = bufff[0]; buf[24] = bufff[1]; buf[25] = bufff[2];
buf[26] = ',';


for(i=0; i<5; i++){                 // 高度可変長対応
if(GGABuf[52+i] == ',')
break;
else
buf[27+i] = GGABuf[52+i];
}
buf[32] = ','; buf[33] = ',';

buf[34] = GGABuf[7]; buf[35] = GGABuf[8]; buf[36] = ':';
buf[37] = GGABuf[9]; buf[38] = GGABuf[10]; buf[39] = ':';
buf[40] = GGABuf[11]; buf[41] = GGABuf[12];
buf[42] = ','; buf[43] = '\n';

FSfwrite((const void*)&buf[0], 1, 44, logFile);
SendState = 1;
}
}

/***************************************
* GPS内容表示サブ関数
* 緯度経度表示
****************************************/
void PosDisp(void)
{
unsigned int i;
/*** 緯度経度表示 ****/
/** 1行目緯度表示 **/
lcd_cmd(0x80); // 1行目
lcd_data(GGABuf[28]); // N/S
lcd_data(' ');
lcd_data(GGABuf[18]); // 緯度表示
lcd_data(GGABuf[19]);
lcd_data(0xDF); // °表示
for(i=0; i<7; i++)
lcd_data(GGABuf[20+i]); // 緯度分表示
lcd_data(' ');
lcd_data('S');
lcd_data(GGABuf[45]); // 衛星数表示
lcd_data(GGABuf[46]);
/** 2行目経度表示 **/
lcd_cmd(0xC0); // 2行目に移動
lcd_data(GGABuf[41]); // E/W
lcd_data(GGABuf[30]);
lcd_data(GGABuf[31]); // 経度表示
lcd_data(GGABuf[32]);
lcd_data(0xDF); // °表示
for(i=0; i<7; i++)
lcd_data(GGABuf[33+i]); // 経度分表示
lcd_data(' ');
lcd_data(GSABuf[9]); // 次元表示
lcd_data('D'); //
}
/***************************************
* GPS内容表示サブ関数
* 時刻表示
****************************************/
void TimeDisp(void){
unsigned char i;
/** 時刻表示 **/
lcd_cmd(0x80); // 1行目
lcd_data('T');
lcd_data(' ');
lcd_data(GGABuf[7]); // 時間
lcd_data(GGABuf[8]);
lcd_data(':');
lcd_data(GGABuf[9]); // 分
lcd_data(GGABuf[10]);
lcd_data(':');
for(i=0; i<2; i++){
lcd_data(GGABuf[11+i]); // 秒
}
/** 高度表示 **/
lcd_cmd(0xC0);
lcd_data('H'); // H表示
lcd_data(' ');
for(i=0; i<5; i++){ // 高度可変長対応
if(GGABuf[52+i] == ',')
break;
else
lcd_data(GGABuf[52+i]); // 高度表示
}
lcd_data(GGABuf[52+i+1]); // M
}
/*********************************************
* バッテリ残量表示サブ関数
*********************************************/
void Battery(void){
/*** バッテリ電圧入力 ***/
AD1CON1bits.ADON = 0; // いったんADオフ
AD1CHS = 0x0001; // チャネルAN1選択
AD1CON1bits.ADON = 1; // AD再度オン
AD1CON1bits.SAMP = 1; // サンプリング開始
while(!AD1CON1bits.DONE); // 変換終了待ち
BatV = ADC1BUF0; // 変換結果取得
/* アイコン表示 */
if(BatV >= 620) // 電圧チェック
lcd_icon(12, 1); // 4.0V以上 多い
else{
if(BatV >= 574)
lcd_icon(11, 1); // 3.7V以上 中容量
else{
if(BatV >= 527)
lcd_icon(10, 1); // 3.4V以上 少容量
else
lcd_icon(9, 1); // 3.4以下 無し
}
}
}


/***********************************************************
* ボーレート変更関数
*
*  条件: USB_CDC_SET_LINE_CODING_HANDLER が定義されていること
************************************************************/
#if defined(USB_CDC_SET_LINE_CODING_HANDLER)
void mySetLineCodingHandler(void)
{
//If the request is not in a valid range
if(cdc_notice.GetLineCoding.dwDTERate.Val > 115200)
{ // 115kbps以上なら何もしない
}
else{
// CDCドライバのボーレート変更
CDCSetBaudRate(cdc_notice.GetLineCoding.dwDTERate.Val);
}
}
#endif





// ***************************************************************************************
// ************** USB Callback Functions *************************************************
// ***************************************************************************************

/*******************************************************************
* Function: void USBCBSuspend(void)
*******************************************************************/
void USBCBSuspend(void)
{
#if 0
U1EIR = 0xFFFF;
U1IR = 0xFFFF;
U1OTGIR = 0xFFFF;
IFS5bits.USB1IF = 0;
IEC5bits.USB1IE = 1;
U1OTGIEbits.ACTVIE = 1;
U1OTGIRbits.ACTVIF = 1;
Sleep();
#endif
}
/*******************************************************************
* Function: void USBCBWakeFromSuspend(void)
*******************************************************************/
void USBCBWakeFromSuspend(void)
{
}
/********************************************************************
Function: void USBCB_SOF_Handler(void)
*******************************************************************/
void USBCB_SOF_Handler(void)
{
}
/*******************************************************************
* Function: void USBCBErrorHandler(void)
*******************************************************************/
void USBCBErrorHandler(void)
{
}
/*******************************************************************
* Function: void USBCBCheckOtherReq(void)
*******************************************************************/
void USBCBCheckOtherReq(void)
{
USBCheckMSDRequest();
}//end
/*******************************************************************
* Function: void USBCBStdSetDscHandler(void)
*******************************************************************/
void USBCBStdSetDscHandler(void)
{
}//end
/*******************************************************************
* Function: void USBCBInitEP(void)
*******************************************************************/
void USBCBInitEP(void)
{
#if (MSD_DATA_IN_EP == MSD_DATA_OUT_EP)
USBEnableEndpoint(MSD_DATA_IN_EP,USB_IN_ENABLED|USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
#else
USBEnableEndpoint(MSD_DATA_IN_EP,USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
USBEnableEndpoint(MSD_DATA_OUT_EP,USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
#endif

USBMSDInit(); // ファイルシステム初期化
CDCInitEP(); // CDCクラス用エンドポイント初期化
}
/*******************************************************************
* Function: void USBCBSendResume(void)
*******************************************************************/
void USBCBSendResume(void)
{
static WORD delay_count;

if(USBGetRemoteWakeupStatus() == TRUE) {
//Verify that the USB bus is in fact suspended, before we send
//remote wakeup signalling.
if(USBIsBusSuspended() == TRUE) {
USBMaskInterrupts();
//Clock switch to settings consistent with normal USB operation.
USBCBWakeFromSuspend();
USBSuspendControl = 0;
USBBusIsSuspended = FALSE; //So we don't execute this code again,
//until a new suspend condition is detected.
delay_count = 3600U;
do {
delay_count--;
}while(delay_count);
//Now drive the resume K-state signalling onto the USB bus.
USBResumeControl = 1; // Start RESUME signaling
delay_count = 1800U; // Set RESUME line for 1-13 ms
do {
delay_count--;
}while(delay_count);
USBResumeControl = 0; //Finished driving resume signalling
USBUnmaskInterrupts();
}
}
}
/*******************************************************************
* Function: BOOL USER_USB_CALLBACK_EVENT_HANDLER
* (USB_EVENT event, void *pdata, WORD size)
*******************************************************************/
BOOL USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void *pdata, WORD size)
{
switch(event)
{
case EVENT_TRANSFER:
lcd_cmd(0xC0);
break;
case EVENT_SOF:
USBCB_SOF_Handler();
break;
case EVENT_SUSPEND:
USBCBSuspend();
break;
case EVENT_RESUME:
USBCBWakeFromSuspend();
break;
case EVENT_CONFIGURED:
USBCBInitEP();
break;
case EVENT_SET_DESCRIPTOR:
USBCBStdSetDscHandler();
break;
case EVENT_EP0_REQUEST:
USBCBCheckOtherReq();
lcd_clear(); // USB接続メッセージ
lcd_str(USBMsg); // LCDに表示
break;
case EVENT_BUS_ERROR:
USBCBErrorHandler();
break;
case EVENT_TRANSFER_TERMINATED:

break;
default:
break;
}
return TRUE;
}